﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YasharEl.Infrastructure.ApplicationModel.Bootstrap.Extensibility;
using YasharEl.Infrastructure.ApplicationModel.Bootstrap.Configuration;
using System.Configuration;
using YasharEl.Infrastructure.Diagnostics.Logging;
using YasharEl.Infrastructure.ObjectFactory;
using YasharEl.Infrastructure.Diagnostics.Configuration;
using YasharEl.Infrastructure.ApplicationModel.Modularity.Bootstrap;

namespace YasharEl.Infrastructure.ApplicationModel.Bootstrap.Extensions
{
    public class LoggingBootstrapperExtension : ModuleComponentBootstrappingExtension, IConsumeConfigurationSection
    {
        #region Properties

        public LoggingConfig LoggingConfigSection { get; private set; }

        #endregion

        #region IConsumeConfigurationSection Members

        public void Apply(ConfigurationSection section)
        {
            LoggingConfigSection = section as LoggingConfig;
        }

        #endregion

        #region BaseComplexBootstrappingExtension Describe

        public override string Describe()
        {
            return "Extension which configure and start logging infrastructure component.";
        }

        #endregion

        #region BaseComplexBootstrappingExtension Configure

        public override void Configure()
        {
            base.Configure();

            if (LoggingConfigSection != null)
            {
                Container.DependencyRegistrar.Register(
                    typeof(ILoggerFactory),
                    LoggingConfigSection.LoggerFactoryType,
                    true
                );

                ILoggerFactory loggerFactory = Container.DependencyResolver.Resolve<ILoggerFactory>();
                loggerFactory.InitializeLoggingFactory(LoggingConfigSection.SettingsFile, ModuleName);

                // Open generic type for ILogger<> Contract.
                Type openGenericLoggerType = typeof(ILogger<>);

                FactoryMethod factoryMethod = new FactoryMethod(
                        (genericType, resolver, requestedType, key)
                            =>
                        {
                            // Is generic logger type like ILogger<BaseBootstrapper>
                            if (requestedType.IsGenericType)
                            {
                                // Create ILogger<> possible one generic type parameter.
                                Type genericArgumentType = requestedType.GetGenericArguments()[0];

                                return loggerFactory.Create(genericArgumentType);
                            }
                            else
                            {
                                // Create ILogger concrete implementation.
                                return loggerFactory.Create(typeof(ILoggerFactory));
                            }
                        }
                );

                // Register loggers factory method to container.
                // For each Resolve logger factory method will create new transient logger per type.
                Container.DependencyRegistrar.RegisterFactory(openGenericLoggerType, factoryMethod);

                Logger.Info("{0} registered as logger factory.", loggerFactory.GetType());
            }
            else
            {
                Logger.Warn("There is no logging configuration found. Use NullLogger by default.");
            }
        }

        #endregion

        #region ModuleComponentBootstrappingExtension Overrides

        public override string SectionName
        {
            get { return LoggingConfig.LoggingConfigDefaultSectionName; }
        }

        #endregion
    }
}
